package com.yyfax.account.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.jaws.core.common.log.Log;
import com.yyfax.account.common.annotation.AccountTradeAnno;
import com.yyfax.account.common.enums.TradeTypeEnum;
import com.yyfax.account.common.exception.AccountExceptionCode;
import com.yyfax.account.vo.BaseTradeReq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.Map;

/**
 * 账户交易工厂，动态扩展交易类型和实现
 * 
 * @author maojian
 * @date 2017-05-27 16:27:41
 * @since v1.0.0
 */
@Service
public class AccountTradeFactory {

	private Logger logger = LoggerFactory.getLogger(getClass());

	@SuppressWarnings("rawtypes")
	private Map<TradeTypeEnum, BaseTradeService> tradeMap = Maps.newHashMap();
	private Map<TradeTypeEnum, Class<? extends BaseTradeReq>> tradeReqTypeMap = Maps.newHashMap();

	@Resource
	ApplicationContext context;

	/**
	 * 初始化tradeMap和tradeReqTypeMap
	 * 
	 * @author maojian
	 * @date 2017-05-27 16:28:12
	 * @since v1.0.0
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@PostConstruct
	void init() {
		Map<String, BaseTradeService> accountMap = context.getBeansOfType(BaseTradeService.class);
		Iterator<Map.Entry<String, BaseTradeService>> iterator = accountMap.entrySet().iterator();
		while (iterator.hasNext()) {
			Map.Entry<String, BaseTradeService> entry = iterator.next();
			AccountTradeAnno assignment = AnnotationUtils.findAnnotation(entry.getValue().getClass(), AccountTradeAnno.class);
			if (null != assignment) {
				Type[] params;
				if (AopUtils.isAopProxy(entry.getValue())) {
					params = ((ParameterizedType) entry.getValue().getClass().getSuperclass().getGenericSuperclass()).getActualTypeArguments();
				} else {
					params = ((ParameterizedType) entry.getValue().getClass().getGenericSuperclass()).getActualTypeArguments();
				}
				tradeMap.put(assignment.value(), entry.getValue());
				tradeReqTypeMap.put(assignment.value(), (Class<? extends BaseTradeReq>) params[0]);
			}
		}

	}

	/**
	 * 动态进行交易对象的转换
	 * 
	 * @author maojian
	 * @date 2017-05-27 16:28:57
	 * @since v1.0.0
	 * @param tradeType
	 * @param json
	 * @return
	 */
	@SuppressWarnings({ "unchecked" })
	public <T extends BaseTradeReq> T covertToTradeReq(TradeTypeEnum tradeType, JSONObject json) {
		return (T) JSON.toJavaObject(json, tradeReqTypeMap.get(tradeType));
	}

	/**
	 * 获取适配的交易实现类
	 * 
	 * @author maojian
	 * @date 2017-05-27 16:29:01
	 * @since v1.0.0
	 * @param tradeType
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public <T extends BaseTradeService> T getAdaptiveTradeService(TradeTypeEnum tradeType) {
		T tradeService = (T) tradeMap.get(tradeType);
		if (null == tradeService) {
			logger.error(Log.op("AccountTradeFactory.getAdaptiveTradeService").msg("账户交易类型不支持").kv("tradeMap", tradeMap).kv("tradeType", tradeType)
					.toString());
			throw AccountExceptionCode.SYS_ERROR.exp();
		}
		return tradeService;
	}

}
